#include <sdl.h>

Uint32 _get_init_flag(Uint32 kyo_flag)
{
    Uint32 flag = SDL_INIT_VIDEO;

    if (kyo_flag & KYO_AUDIO)
        flag |= SDL_INIT_AUDIO;

    return flag;
}

Uint32 _get_video_flag(Uint32 kyo_flag)
{
    Uint32 flag = SDL_SWSURFACE;

    return flag;
}

int _init_sdl_flag(KYO_SDL *sdl, Uint32 kyo_flag)
{
    int ret;

    if (kyo_flag & KYO_IMG)
    {
        ret = IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF);
        SDL_ERRP(-1 == ret, goto ERR1, 2, "IMG_Init failed!\n");
        sdl->init_img = 1;
    }


    if (kyo_flag & KYO_TTF)
    {
        ret = TTF_Init();
        SDL_ERRP(-1 == ret, goto ERR1, 2, "TTF_Init failed!\n");
        sdl->init_ttf = 1;
    }

    if (kyo_flag & KYO_AUDIO)
    {
        ret = Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, KYO_BUF_MAX);
        SDL_ERRP(-1 == ret, goto ERR1, 2, "Mix_OpenAudio failed!\n");
        sdl->init_audio = 1;
    }

    return 0;
ERR1:
    return -1;
}

int sdl_pro_quit(SDLKey key, Uint32 state, void *data)
{
    KYO_SDL *sdl = (KYO_SDL *)data;

    sdl->quit = 1;
}

KYO_SDL *sdl_init(Uint16 w, Uint16 h, Uint8 bpp, Uint32 flag)
{
    KYO_SDL *sdl = NULL;
    int ret;

    sdl = (KYO_SDL *)malloc(sizeof(KYO_SDL));
    SDL_ERRP(NULL == sdl, goto ERR1, 2, "malloc KYO_SDL failed!\n");

    bzero(sdl, sizeof(KYO_SDL));

    ret = SDL_Init(_get_init_flag(flag));
    SDL_ERRP(-1 == ret, goto ERR2, 2, "SDL_Init: %s!\n", SDL_GetError());

    sdl->screen = SDL_SetVideoMode(w, h, bpp, _get_video_flag(flag));
    SDL_ERRP(NULL == sdl->screen, goto ERR2, 2, "SDL_Init: %s!\n", SDL_GetError());

    ret = _init_sdl_flag(sdl, flag);
    SDL_ERRP(-1 == ret, goto ERR2, 0);

    sdl->old_quit_key = SDLK_ESCAPE;

    sdl_bind_key(sdl, sdl->old_quit_key, SDL_KEYDOWN, sdl_pro_quit, sdl);

    return sdl;
ERR2:
    sdl_exit(&sdl);
ERR1:
    return NULL;
}

Uint32 sdl_bind_key(KYO_SDL *sdl, SDLKey key, Uint8 state, sdl_key_handle_t *handle, void *data)
{
    SDL_ERRP(key < SDLK_FIRST || key >= SDLK_LAST
             || !(state == SDL_KEYDOWN || state == SDL_KEYUP),
                return 1, 0);

    state -= SDL_KEYDOWN;

    if (handle == sdl_pro_quit)
        sdl->old_quit_key = key;

    sdl->key[state][key].handle = handle;
    sdl->key[state][key].data = data;

    return 0;
}

Uint32 sdl_unbind_key(KYO_SDL *sdl, SDLKey key, Uint8 state)
{
    return sdl_bind_key(sdl, key, state, NULL, NULL);
}

Uint32 sdl_register_quit(KYO_SDL *sdl, SDLKey key, sdl_quit_handle_t *handle, void *data)
{
    if (key != 0)
    {
        sdl_unbind_key(sdl, sdl->old_quit_key, SDL_KEYDOWN);
        sdl_bind_key(sdl, key, SDL_KEYDOWN, sdl_pro_quit, sdl);
    }

    sdl->quit_handle = handle;
    sdl->quit_data = data;

    return 0;
}

Uint32 sdl_run(KYO_SDL *sdl, Uint8 exit)
{
    SDL_Event event;
    int state, key;

    while (!sdl->quit)
    {
        if (SDL_WaitEvent(&event))
        {
            if (event.type == SDL_QUIT)
                break;
            else if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP)
            {
                state = event.type - SDL_KEYDOWN;
                key = event.key.keysym.sym;
                if (sdl->key[state][key].handle &&
                    sdl->key[state][key].handle(key, event.type, sdl->key[state][key].data) == KYO_SDL_QUIT)
                    break;
            }
        }
    }

    if (sdl->quit_handle)
        sdl->quit_handle(sdl->quit_data);

    if (exit)
        sdl_exit(&sdl);

    return 0;
}

void sdl_exit(KYO_SDL **kyo_sdl)
{
    KYO_SDL *sdl = *kyo_sdl;

    if (sdl->init_img)
        IMG_Quit();

    if (sdl->init_ttf)
        TTF_Quit();

    if (sdl->init_audio)
        Mix_CloseAudio();

    SDL_FreeSurface(sdl->screen);
    free(sdl);
    *kyo_sdl = NULL;
    SDL_Quit();
}

void draw_pixel(SDL_Surface *dst, int x, int y, Uint32 color)
{
    SDL_Rect offset = {0, 0, 1, 1};

    offset.x = x;
    offset.y = y;

    SDL_FillRect(dst, &offset, SDL_MapRGB(dst->format,
                            (char)(color >> 16),
                            (char)(color >> 8),
                            (char)color));
}

void draw_vline(SDL_Surface *dst, int x, int y, int len, Uint32 color)
{
    SDL_Rect offset = {0, 0, 1, 1};

    offset.x = x;
    offset.y = y;
    offset.h = len;

    SDL_FillRect(dst, &offset, SDL_MapRGB(dst->format,
                            (char)(color >> 16),
                            (char)(color >> 8),
                            (char)color));
}

void draw_hline(SDL_Surface *dst, int x, int y, int len, Uint32 color)
{
    SDL_Rect offset = {0, 0, 1, 1};

    offset.x = x;
    offset.y = y;
    offset.w = len;

    SDL_FillRect(dst, &offset, SDL_MapRGB(dst->format,
                            (char)(color >> 16),
                            (char)(color >> 8),
                            (char)color));
}

void draw_rect(SDL_Surface *dst, int x, int y, int w, int h, Uint32 color)
{
    SDL_Rect offset = {0, 0, 1, 1};

    offset.x = x;
    offset.y = y;
    offset.w = w;
    offset.h = h;

    SDL_FillRect(dst, &offset, SDL_MapRGB(dst->format,
                            (char)(color >> 16),
                            (char)(color >> 8),
                            (char)color));
}


void draw_box(SDL_Surface *dst, int x, int y, int w, int h, int border, Uint32 border_color, Uint32 color)
{
    draw_rect(dst, x, y, w, h, border_color);
    draw_rect(dst, x + border, y + border, w - 2 * border, h - border * 2, color);
}

void draw_circle(SDL_Surface *dst, int x, int y, int r, Uint32 color)
{
    int i, j, h = y + r, w = x + r;

    for (i = y - r; i <= h; i++)
    {
        for (j = x - r; j <= w; j++)
        {
            if ((y - i) * (y - i) +  (x - j) * (x - j) <= r * r)
                draw_pixel(dst, j, i, color);
        }
    }

}

SDL_Surface *pic_load(const char *file)
{
    SDL_Surface *op = NULL, *img = NULL;

    op = IMG_Load(file);
    if (op != NULL)
    {
        img = SDL_DisplayFormat(op);
        SDL_FreeSurface(op);
    }

    return img;
}

